import ProtocolEnum from "../../game/common/ProtocolEnum";
import MsgMgr from "../../lib/event/MsgMgr";
import StartUp from "../../lib/StartUp";
import Cmd from "./Cmd";
import Http from "./Http";
import { Socket, SOCK_STATE } from "./Socket";


export enum NetMethod {
    GET,
    POST,
    SOCKET,
    WAIT_SOCKET,
}

class MsgUnit {
    public id:number;
    public param:any;
    public func:any;
    public method:NetMethod;
}

class RetryUnit {
    public delay:number;
    public times:number;
}


const {ccclass, property} = cc._decorator;



@ccclass
export default class NetMgr extends cc.Component {

    protected static _instance:NetMgr = null;
    public static get instance():NetMgr {
        if (NetMgr._instance == null) {
            let node = new cc.Node();
            node.name = "NetMgr";
            NetMgr._instance = node.addComponent(NetMgr);
            StartUp.instance.gameRoot.addChild(node);
        }
        return NetMgr._instance;
    }

    private list:Array<MsgUnit> = new Array();
    private http:Http;
    private sock:Socket;
    private errorHandler:any;

    private heartTime:number = 0;
    private socketRetry:number = 0;
    private retryList:Array<RetryUnit> = new Array();

    public connectHttp(url) {
        this.http = new Http();
        this.http.url = url;
    }

    public connectSocket(url, func) {
        this.sock = new Socket();
        //this.sock.session = this.http.session;
        this.sock.connect(url, func);
    }

    public closeSocket() {
        this.sock.clean();
    }

    public send(id, param, func, method:NetMethod) {
        let unit = new MsgUnit();
        unit.id = id;
        unit.param = param;
        unit.func = func;
        unit.method = method;
        this.list.push(unit);
    }

    public regisErrorHandler(errorHandler) {
        this.errorHandler = errorHandler;
        Http.errorHandler = errorHandler;
        Socket.errorHandler = errorHandler;
    }

    public setNetSession(session) {
        this.http && (this.http.session = session);
        this.sock && (this.sock.session = session);
    }

    private msgHandler(unit:MsgUnit) {
        if (unit.method == NetMethod.SOCKET) {
            //长链接
            this.sock && this.sock.send(unit.id, unit.param, unit.func);
        } else if (unit.method == NetMethod.GET) {
            this.http && this.http.send(unit.id, unit.param, unit.func);
        } else if (unit.method == NetMethod.POST) {
            this.http && this.http.post(unit.id, unit.param, unit.func);
        } else if (unit.method = NetMethod.WAIT_SOCKET) {
            this.sock && this.sock.wait(unit.id, unit.func);
        }
    }

    protected update(dt: number): void {
        this.updateNet(dt);
        this.updateSocketHeart(dt);
        this.checkSocket();
        this.updateRetry(dt);
    }

    private updateNet(dt: number) {
        if (this.list.length <= 0) { return; }
        let unit = this.list[0];
        this.list.splice(0, 1);
        this.msgHandler(unit);
    }

    //60秒发送一次心跳
    private updateSocketHeart(dt) {
        if (this.sock == null || this.sock.state != SOCK_STATE.SUCCESS) { return; }
        this.heartTime -= dt;
        if (this.heartTime <= 0) {
            //console.error("发送长链接心跳")
            this.heartTime = 60;
            
            //this.send(ProtocolEnum.SOCKET_REQUST_TEST, encodeHelloReq({name:"jackson"}), function(){}.bind(this), NetMethod.SOCKET);
        }
    }

    private updateRetry(dt) {
        if (this.retryList.length <= 0) { return; }

        if (this.retryList[0].times >= 5) {
            this.retryList.length = 0;
            this.sock = null;
            MsgMgr.emit("ON_NET_ERROR");//抛出网络错误的消息
            return; 
        }

        this.retryList[0].delay -= dt;
        if (this.retryList[0].delay <= 0) {
            this.retryList.splice(0, 1);
            this.sock.reconnect(function(result){
                if (result) {
                    this.socketRetry = 0;
                    this.retryList.length = 0;
                }
            }.bind(this));
        }
    }

    //socket断线后重连
    private checkSocket() {
        if (this.sock && this.sock.state == SOCK_STATE.ERROR && this.retryList.length <= 0) {
            //socket 断开
            let retry = new RetryUnit();
            retry.delay = 5;
            retry.times = this.socketRetry++;
            this.retryList.push(retry);
            
        }
    }

}